package yartiss.engine.simulation.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import yartiss.engine.simulation.system.ITask;
import yartiss.engine.simulation.system.schedulable.GraphTask;
import yartiss.engine.simulation.system.schedulable.SchedulableFactory;
import yartiss.engine.simulation.system.schedulable.SubTask;

/**
 * 
 * @author Manar Qamhieh
 * 
 */
public class  XmlFileReader {
	private final InputStream input;

	private final SAXParser parser;

	protected List<List<ITask>> tasksets;
	protected List<ITask> tasks;

	public XmlFileReader(File file) throws Exception {
		this(new FileInputStream(file));
	}

	public XmlFileReader(String fileName) throws Exception {
		this(new FileInputStream(fileName));
	}

	public XmlFileReader(InputStream input)
			throws ParserConfigurationException, SAXException {
		this.input = input;
		SAXParserFactory factory = SAXParserFactory.newInstance();
		factory.setNamespaceAware(true);
		parser = factory.newSAXParser();
	}

	public List<List<ITask>> readTasksets() throws FileNotFoundException,
			SAXException, IOException {
		parser.parse(input, this.getDefaultHandler());
		return tasksets;
	}

	protected DefaultHandler getDefaultHandler() {
		return new DefaultHandler() {

			private ITask task;
			private List<SubTask> subtasks;
			private String type;
			int nbTasks;
			private HashMap<String, Object> taskMap, subtaskMap;

			@Override
			public void startElement(String uri, String localName,
					String qName, Attributes attributes) throws SAXException {

				if ("dataset".equals(localName)) {
					int nbTasksets = Integer.parseInt(attributes
							.getValue("nbTasksets"));
					nbTasks = Integer.parseInt(attributes.getValue("nbTasks"));
					tasksets = new ArrayList<List<ITask>>(nbTasksets);

				} else if ("taskset".equals(localName)) {
					// Do nothing for the moment
					tasks = new ArrayList<ITask>(nbTasks);

				} else if ("task".equals(localName)) {
					type = attributes.getValue("type");

					taskMap = new HashMap<String, Object>();
					taskMap.put("type", type);
					String param = type.toLowerCase();
					if("simple".equals(param)){

						taskMap.put("firstrelease",
								attributes.getValue("firstRelease"));
						taskMap.put("wcet", attributes.getValue("wcet"));
						taskMap.put("wcee", attributes.getValue("wcee"));
						taskMap.put("period", attributes.getValue("period"));
						taskMap.put("deadline", attributes.getValue("deadline"));
						taskMap.put("priority", attributes.getValue("priority"));
						task = SchedulableFactory.newInstance(taskMap);
					}
					else if("graph".equals(param)){

						subtasks = new ArrayList<SubTask>(
								Integer.parseInt(attributes
										.getValue("nbSubtasks")));
						taskMap.put("firstrelease",
								attributes.getValue("firstRelease"));
						taskMap.put("period", attributes.getValue("period"));
						taskMap.put("deadline", attributes.getValue("deadline"));
						taskMap.put("priority", attributes.getValue("priority"));

					}
					else if("subtask".equals(param));
					else 
						throw new IllegalArgumentException(
								"Illegal task type...");

				} 
				else if ("subtask".equals(localName)) {
					subtaskMap = new HashMap<String, Object>();
					subtaskMap.put("type", attributes.getValue("type"));
					subtaskMap.put("firstrelease",
							attributes.getValue("firstRelease"));
					subtaskMap.put("wcee", "0");
					subtaskMap.put("wcet", attributes.getValue("wcet"));
					subtaskMap.put("period", attributes.getValue("period"));
					subtaskMap.put("deadline", attributes.getValue("deadline"));
					subtaskMap.put("priority", attributes.getValue("priority"));
					subtaskMap.put("nbproc", attributes.getValue("nbProc"));

					SubTask subtask = (SubTask) SchedulableFactory
							.newInstance(subtaskMap);
					subtask.setChildrenIndices(attributes.getValue("children")
							.trim().split(" "));
					subtask.setId(Integer.parseInt(attributes.getValue("index")));
					subtasks.add(subtask);

				}
				super.startElement(uri, localName, qName, attributes);
			}

			@Override
			public void endElement(String uri, String localName, String qName)
					throws SAXException {

				if ("taskset".equals(localName)) {
					if (!tasks.isEmpty()) {
						tasksets.add(tasks);
					}
				} else if ("task".equals(localName)) {
					if (!subtasks.isEmpty()) {
						taskMap.put("tasks", subtasks);

						task = SchedulableFactory.newInstance(taskMap);
						for (SubTask sub : ((GraphTask) task).getSubtasks()) {
							if (sub.getChildrenIndices() == null)
								continue;
							if (sub.getChildrenIndices().contains(-1))
								continue;
							for (SubTask sub2 : ((GraphTask) task)
									.getSubtasks()) {
								if ((sub.getChildrenIndices().contains(sub2
										.getId())) && !sub.equals(sub2)) {
									sub.addChildTask(sub2);
								}
							}
						}

						// TODO integrate children relations...
					}
					if (task != null) {
						tasks.add(task);

						// System.out.println("Task: " + task.toString());
						// GraphTask graph = (GraphTask) task;
						// for (SubTask subtask : graph.getSubtasks()) {
						//
						// System.out.println("***subtask: "
						// + subtask.toString());
						//
						// }
					}

				}
				super.endElement(uri, localName, qName);
			}

			@Override
			public void characters(char[] ch, int start, int length)
					throws SAXException {
				super.characters(ch, start, length);
			}

		};
	}
}
